-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
WIP: Call overload #8008
WIP: Call overload #8008
Conversation
…call(f, x...) as a fallback (if f is not a function); to do: update inference, fallback to call when f is a type
I felt it might be useful to just put up the entire log of my debugging session, as a demo: This looks fun. Somewhere between trying to create an array, and eval'ing some Expr, this code jumped in and tried to call |
Working on this now. |
Yay! |
Conflicts: src/codegen.cpp test/core.jl
Somewhat amazingly, the build passed. However now we have to figure out how to scope
This is easy to handle in codegen since it knows what module the current function is in. However there is no way to do this from |
A quick survey reveals |
My thinking was that |
Of these, only TermWin.jl by @tonyhffong seems to use |
I'm pretty sure we can remove any uses of |
It's nice to have |
Splatting is lowered to call |
Although I'm not following the discussion, I can work around that as well if this should be deprecated. |
2ef98c5
to
0388647
Compare
Conflicts: base/base.jl test/core.jl
I found one kind of situation where calling However this is not super compelling, since it doesn't generalize --- it only goes one level deeper into the argument. To get another level you'd need |
- look up call in the right module instead of using jl_call_func - some inference support for call overloading - pass `call` to _apply and kwcall so they use the containing module's definition - deprecate explicit apply(), rename the builtin to _apply
Conflicts: base/deprecated.jl base/inference.jl
Sadly this branch now seems to have a 3-4x longer startup time than master. No idea why yet. |
It seems like most of the slowdown is running inference on the initial |
Since the inner/outer constructor business is one of the biggest causes of confusion in the current system, I think that some generalization and change there may well not be a bad thing at all. Excited to see how this pans out. I still wonder if the "everything is one big generic apply function" model isn't good. |
There is a subtle issue with the "everything is one generic apply function" model: it becomes impossible, in some sense, to actually pass functionality to somebody else. If I pass you |
Interesting. I'll have to think about that. |
What if there is only one |
Well, of course that is what allows the idea to work and might mean the "problem" is only psychological. I'm thinking from an ABI perspective. You would have to work to enforce the "only one Another way to look at it is that every "function" is inherently in two places that need to be kept in sync: first you make a "token" for a function, then you must insert it in a global table, then I can pass it to you. As opposed to simply having a function object that I pass a pointer to. Still another way to look at it is that our C API can give you a C-callable function pointer to some julia code. So there is in fact some underlying "callable object", but it's not a first-class object in the language. Again, none of this actually breaks anything; it may only be a matter of compiler and linker efficiency. |
@JeffBezanson what you're describing sounds a lot like a |
Kind of, but julia doesn't do anything at compile time except as an optimization, so you have to think about running pieces of code passing stuff around. One can imagine enforcing "only one Now we want to use both of these libraries in a single process. What happens? With a single From this thought experiment I conclude that having multiple separate first-class generic functions is a useful abstraction. However I'm not quite sure when to use them. With this branch we already have the choice of making a new generic function, or overloading |
I wouldn't say I'm surprised, but it's still kind of amazing that there are 778 constructors in Base. |
That's pretty nuts / cool. |
It's also kind of nice to make these all methods of a single generic function. Feels much more first class. |
it's almost like the Type should contain an environment field and perhaps a lambda info too that points to the function that should be used when "calling" that typename. oh, wait – that's exactly what we have now. oops, hmm... |
@@ -186,6 +186,12 @@ const Nothing = Void | |||
export None | |||
const None = Union() | |||
|
|||
export apply | |||
function apply(f, args...) | |||
depwarn("apply() is deprecated, use `...` instead", :apply) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
apply(f, x) is deprecated, use
f(x...) instead
Recording here that @vtjnash mentioned a good reason to consider merging #8656 before this (#8656 (comment)). |
@@ -446,6 +447,17 @@ void jl_module_run_initializer(jl_module_t *m) | |||
} | |||
} | |||
|
|||
jl_function_t *jl_module_call_func(jl_module_t *m) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you transform x(...)
into call(x, ...)
, shouldn't this always use Base.call
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It can't, because there isn't just one Base
(during bootstrap). In practice, everybody will use Base.call
, like we use Base.convert
now, but we at least want to preserve the possibility of a module with a separate call
.
Since outer constructors always appear after the type definition, it doesn't seem too impractical to detect that the function name is a type and convert them to Besides backwards compatibility, I think it would just be too confusing to require |
Yes, I agree. I think this is in pretty good shape now. I find that the constructor change can be detrimental to type information. For example:
Previously, we knew that the first two methods were the only constructors for |
Some of that could be reclaimed with monotonic dispatch as @toivoh once proposed. |
Why do we need It seems like the only fallback that we really need is |
I've considered explicitly "importing" |
superseded by #8712. |
@stevengj Turning this into a PR so that I can comment on it easier.